package com.ys.service.flow.impl;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ys.entity.flow.YspDef;
import com.ys.entity.flow.YspDefLink;
import com.ys.entity.flow.YspDefNode;
import com.ys.entity.flow.YspDeploy;
import com.ys.entity.flow.YspModel;
import com.ys.enume.flow.YspDefLinkEnum;
import com.ys.enume.flow.YspDefNodeEnum;
import com.ys.mapper.flow.YspDefLinkMapper;
import com.ys.mapper.flow.YspDefMapper;
import com.ys.mapper.flow.YspDefNodeMapper;
import com.ys.mapper.flow.YspDeployMapper;
import com.ys.mapper.flow.YspModelMapper;
import com.ys.service.flow.YspModelService;
import com.ys.vo.R;

@Service("yspModelService")
public class YspModelServiceImpl implements YspModelService {

	@Autowired
	private YspDefMapper yspDefMapper;
	@Autowired
	private YspDefNodeMapper yspDefNodeMapper;
	@Autowired
	private YspDefLinkMapper yspDefLinkMapper;
	@Autowired
	private YspDeployMapper yspDeployMapper;
	@Autowired
	private YspModelMapper yspModelMapper;

	@Override
	public R add(Map<String, Object> params) {
		
		YspModel entity = JSON.parseObject(JSON.toJSONString(params), YspModel.class);
		
		// 验证编码
		String code = params.get("code").toString();
		if (new YspModel().setCode(code).count() > 0) {
			return R.error("编码已存在");
		}
		entity.setStatus(1)
			.setInfo("{\"class\":\"go.GraphLinksModel\",\"linkFromPortIdProperty\":\"fromPort\",\"linkToPortIdProperty\":\"toPort\",\"nodeDataArray\":[{\"key\":-1,\"category\":\"Start\",\"loc\":\"175 0\",\"text\":\"开始\"},{\"key\":-2,\"category\":\"End\",\"loc\":\"175 180\",\"text\":\"结束\"}],\"linkDataArray\":[]}")
			.setVersionLatest(0);
		
		yspModelMapper.insert(entity);
		
		return R.ok();
	}

	@Override
	@Transactional
	public R save(String body) {
		JSONObject bodyJO = JSON.parseObject(body);
		
		if (!bodyJO.containsKey("id")) {
			return R.error("ID不能为空");
		}
		Long id = bodyJO.getLong("id");
		bodyJO.remove("id");
		
		// 节点数据
		JSONArray nodeJA = bodyJO.getJSONArray("nodeDataArray");
		Map<Integer, JSONObject> KEY_NODE_MAP = new HashMap<Integer, JSONObject>();
		for(int i = 0; i < nodeJA.size(); i++) {
			JSONObject nodeJO = nodeJA.getJSONObject(i);
			KEY_NODE_MAP.put(nodeJO.getInteger("key"), nodeJO);
		}
		// 连接线数据
		JSONArray linkJA = bodyJO.getJSONArray("linkDataArray");
		Map<Integer, JSONArray> FROM_LINKS_MAP = new HashMap<Integer, JSONArray>();
		Map<Integer, JSONArray> TO_LINKS_MAP = new HashMap<Integer, JSONArray>();
		for(int i = 0; i < linkJA.size(); i++) {
			JSONObject linkJO = linkJA.getJSONObject(i);
			// 把同一起始点的链接放入MAP
			Integer keyFrom = linkJO.getInteger("from");
			JSONArray JAFrom = null;
			if (FROM_LINKS_MAP.containsKey(keyFrom)) {
				JAFrom = FROM_LINKS_MAP.get(keyFrom);
			} else {
				JAFrom = new JSONArray();
			}
			JAFrom.add(linkJO);
			FROM_LINKS_MAP.put(keyFrom, JAFrom);

			// 把同一到达点的链接放入MAP
			Integer keyTo = linkJO.getInteger("to");
			JSONArray JATo = null;
			if (TO_LINKS_MAP.containsKey(keyTo)) {
				JATo = TO_LINKS_MAP.get(keyTo);
			} else {
				JATo = new JSONArray();
			}
			JATo.add(linkJO);
			TO_LINKS_MAP.put(keyTo, JATo);
		}
		
		CheckModelDto checkModelDto = checkModel(body);
		if (checkModelDto.isFlag() == false) {
			return R.error(checkModelDto.getMsg());
		}
		
		
		YspModel entity = new YspModel().setId(id).queryFirst();
		if (entity == null) {
			return R.error("流程模型不存在");
		}
		entity.setInfo(bodyJO.toJSONString());
		yspModelMapper.update(entity);
		
		return R.ok();
	}

	@Override
	public R deploy(Long id) {
		
		if (id == null) {
			return R.error("ID不能为空");
		}
		YspModel entity = new YspModel().setId(id).queryFirst();
		if (entity == null) {
			return R.error("流程模型不存在");
		}
		
		// 验证模型的完整性
		CheckModelDto checkModelDto = checkModel(entity.getInfo());
		if (checkModelDto.isFlag() == false) {
			return R.error(checkModelDto.getMsg());
		}
		
		// 添加部署
		YspDeploy yspDeploy = null;
		{
			Long modelId = id;
			Integer version = entity.getVersionLatest() + 1;
			String info = entity.getInfo();
			yspDeploy = YspDeploy.yspDeploy(modelId, version, info, 1);
			yspDeployMapper.insert(yspDeploy);
		}
		
		// 添加流程定义
		YspDef yspDef = null;
		{
			Long deployId = yspDeploy.getId();
			String code = entity.getCode() + "-" + yspDeploy.getVersion();
			String name = entity.getName();
			yspDef = YspDef.yspDef(deployId, code, name, 1);
			yspDefMapper.insert(yspDef);
		}

		JSONObject infoJO = JSON.parseObject(entity.getInfo());
		JSONArray nodeJA = infoJO.getJSONArray("nodeDataArray");
		// 记录节点KEY-节点ID的MAP
		Map<Integer, Long> KEY_ID_MAP = new HashMap<Integer, Long>();
		// 添加流程定义节点
		for(int i = 0; i < nodeJA.size(); i++) {
			JSONObject nodeJO = nodeJA.getJSONObject(i);
			Long defId = yspDef.getId();
			Integer type = YspDefNodeEnum.Type.getValue(nodeJO.getString("category"));
			String name = nodeJO.getString("text");
			String info = nodeJO.toJSONString();
			Integer auditorType = nodeJO.getInteger("auditorType");
			String auditorValue = nodeJO.getString("auditorValue");
			YspDefNode yspDefNode = YspDefNode.yspDefNode(defId, type, name, auditorType, auditorValue, info, 1);
			yspDefNodeMapper.insert(yspDefNode);
			KEY_ID_MAP.put(nodeJO.getInteger("key"), yspDefNode.getId());
		}

		JSONArray linkJA = infoJO.getJSONArray("linkDataArray");
		// 添加流程定义链接
		for(int i = 0; i < linkJA.size(); i++) {
			JSONObject linkJO = linkJA.getJSONObject(i);
			Long defId = yspDef.getId();
			Long nodeIdFrom = KEY_ID_MAP.get(linkJO.getInteger("from"));
			Long nodeIdTo = KEY_ID_MAP.get(linkJO.getInteger("to"));
			String info = linkJO.toJSONString();
			Integer condResult = linkJO.getInteger("condResult");
			YspDefLink yspDefLink = YspDefLink.yspDefLink(defId, nodeIdFrom, nodeIdTo, condResult, info, 1);
			yspDefLinkMapper.insert(yspDefLink);
		}
		
		entity.setVersionLatest(yspDeploy.getVersion());
		yspModelMapper.update(entity);
		return R.ok();
	}

	/**
	 * 验证模型的完整性
	 */
	@Override
	public CheckModelDto checkModel(String info) {

		JSONObject infoJO = JSON.parseObject(info);
		
		// 节点数据
		JSONArray nodeJA = infoJO.getJSONArray("nodeDataArray");
		Map<Integer, JSONObject> KEY_NODE_MAP = new HashMap<Integer, JSONObject>();
		for(int i = 0; i < nodeJA.size(); i++) {
			JSONObject nodeJO = nodeJA.getJSONObject(i);
			KEY_NODE_MAP.put(nodeJO.getInteger("key"), nodeJO);
		}
		// 连接线数据
		JSONArray linkJA = infoJO.getJSONArray("linkDataArray");
		Map<Integer, JSONArray> FROM_LINKS_MAP = new HashMap<Integer, JSONArray>();
		Map<Integer, JSONArray> TO_LINKS_MAP = new HashMap<Integer, JSONArray>();
		for(int i = 0; i < linkJA.size(); i++) {
			JSONObject linkJO = linkJA.getJSONObject(i);
			// 把同一起始点的链接放入MAP
			Integer keyFrom = linkJO.getInteger("from");
			JSONArray JAFrom = null;
			if (FROM_LINKS_MAP.containsKey(keyFrom)) {
				JAFrom = FROM_LINKS_MAP.get(keyFrom);
			} else {
				JAFrom = new JSONArray();
			}
			JAFrom.add(linkJO);
			FROM_LINKS_MAP.put(keyFrom, JAFrom);

			// 把同一到达点的链接放入MAP
			Integer keyTo = linkJO.getInteger("to");
			JSONArray JATo = null;
			if (TO_LINKS_MAP.containsKey(keyTo)) {
				JATo = TO_LINKS_MAP.get(keyTo);
			} else {
				JATo = new JSONArray();
			}
			JATo.add(linkJO);
			TO_LINKS_MAP.put(keyTo, JATo);
		}
		
		/*
		 * 验证节点格式
		 * 1、每个节点都要有连接线
		 * 2、开始节点只有一条FROM连接线
		 * 3、结束节点至少一条TO连接线
		 * 4、条件节点至少一条TO连接线，只有两条FROM连接线，必须要有判断条件
		 * 5、执行节点至少一条TO连接线，只有一条FROM连接线
		 */
		for (int i = 0; i < nodeJA.size(); i++) {
			JSONObject nodeJO = nodeJA.getJSONObject(i);
			Integer key = nodeJO.getInteger("key");
			
			String category = nodeJO.getString("category");
			if ("Start".equals(category)) {
				if (!FROM_LINKS_MAP.containsKey(key) || FROM_LINKS_MAP.get(key).size() != 1) {
					return new CheckModelDto(false, "开始节点只能有一条连接线");
				}
				
			} else if ("End".equals(category)) {
				if (!TO_LINKS_MAP.containsKey(key) || TO_LINKS_MAP.get(key).size() == 0) {
					return new CheckModelDto(false, "结束节点至少要有一条连接线");
				}
			} else if ("Conditional".equals(category)) {
				if (!TO_LINKS_MAP.containsKey(key) || TO_LINKS_MAP.get(key).size() == 0) {
					return new CheckModelDto(false, "条件节点至少要有一条TO连接线");
				}
				if (!FROM_LINKS_MAP.containsKey(key) || FROM_LINKS_MAP.get(key).size() != 2) {
					return new CheckModelDto(false, "条件节点只能有两条FROM连接线");
				}
				JSONArray JAFrom = FROM_LINKS_MAP.get(key);
				Integer condResult1 = JAFrom.getJSONObject(0).getInteger("condResult");
				Integer condResult2 = JAFrom.getJSONObject(1).getInteger("condResult");
				if (condResult1 == YspDefLinkEnum.CondResult.NO.value) {
					if (condResult2 != YspDefLinkEnum.CondResult.YES.value) {
						return new CheckModelDto(false, "条件节点判断结果必须包含是否");
					}
				} else if (condResult1 == YspDefLinkEnum.CondResult.YES.value) {
					if (condResult2 != YspDefLinkEnum.CondResult.NO.value) {
						return new CheckModelDto(false, "条件节点判断结果必须包含是否");
					}
				} else {
					return new CheckModelDto(false, "条件节点判断结果必须包含是否");
				}
				
				if (!nodeJO.containsKey("cond")) {
					return new CheckModelDto(false, "判断条件不能为空");
				} else {
					String cond = nodeJO.getString("cond");
					if (cond == null || cond.length() == 0) {
						return new CheckModelDto(false, "判断条件不能为空");
					}
				}
			} else if ("Default".equals(category)) {
				if (!TO_LINKS_MAP.containsKey(key) || TO_LINKS_MAP.get(key).size() == 0) {
					return new CheckModelDto(false, "执行节点至少要有一条TO连接线");
				}
				if (!FROM_LINKS_MAP.containsKey(key) || FROM_LINKS_MAP.get(key).size() != 1) {
					return new CheckModelDto(false, "执行节点只能有一条FROM连接线");
				}
				Integer auditorType = nodeJO.getInteger("auditorType");
				if (auditorType == null) {
					return new CheckModelDto(false, "审核员类型不能为空");
				} else if (auditorType == YspDefNodeEnum.AuditorType.USER_POINTED.value
						|| auditorType == YspDefNodeEnum.AuditorType.ROLE_AND.value
						|| auditorType == YspDefNodeEnum.AuditorType.ROLE_OR.value
						|| auditorType == YspDefNodeEnum.AuditorType.SCRIPT_POINT.value) {
					String auditorValue = nodeJO.getString("auditorValue");
					if (auditorValue == null || auditorValue.length() == 0) {
						return new CheckModelDto(false, "审核员类型为指定时，必须填写指定值");
					}
				}
			}
		}
		
		return new CheckModelDto(true, null);
	}

	@Override
	public R delete(Long id) {
		
		if (id == null) {
			return R.error("ID不能为空");
		}
		YspModel entity = new YspModel().setId(id).queryFirst();
		if (entity == null) {
			return R.error("流程模型不存在");
		}
		
		entity.setStatus(0);
		yspModelMapper.update(entity);
		return R.ok();
	}
}
